home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / ALLOC.C next >
Encoding:
C/C++ Source or Header  |  1997-07-30  |  13.9 KB  |  585 lines

  1.  
  2. #ifdef MSDOS
  3. /* memory allocation routines
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  *
  6.  * Adapted from alloc routine in K&R; memory statistics and interrupt
  7.  * protection added for use with net package. Must be used in place of
  8.  * standard Turbo-C library routines because the latter check for stack/heap
  9.  * collisions. This causes erroneous failures because process stacks are
  10.  * allocated off the heap.
  11.  *
  12.  * Mods by G1EMM , PA0GRI, KO4KS
  13.  */
  14.  
  15. #define __dj_include_stdlib_h_
  16. #include "global.h"
  17. #define FP_OFF( fp )( (unsigned )( fp ))
  18. #include "proc.h"
  19. #include "socket.h"
  20. #include "commands.h"
  21. #include <dpmi.h>
  22.  
  23. #if !defined(_lint)
  24. static char rcsid[] OPTIONAL = "$Id: alloc.c,v 1.20 1997/07/31 00:44:20 root Exp root $";
  25. #endif
  26.  
  27. static unsigned long Memfail = 0;    /* Count of allocation failures */
  28. static unsigned long Allocs = 0;    /* Total allocations */
  29. static unsigned long Frees = 0;        /* Total frees */
  30. static unsigned long Invalid = 0;    /* Total calls to free with garbage arg */
  31. static unsigned long Yellows = 0;    /* Yellow alert garbage collections */
  32. static unsigned long Reds = 0;        /* Red alert garbage collections */
  33. static int Memwait;            /* Number of tasks waiting for memory */
  34. static unsigned long Availmem = 0;    /* Heap memory, ABLKSIZE units */
  35. static unsigned long Morecores = 0;
  36. static int Memdebug = 0;        /* 0 = normal, 1 = call logstat() */
  37. static char freewarn[] ="free: WARNING! %s (%08x) pc = %04x:%04x proc %s%c";
  38. static char freewarn1[] = "invalid pointer";
  39. static char HeapSizeStr[] = "heap size %lu, avail %lu (%lu%%), morecores %lu";
  40. #ifdef Kelvdebug
  41. static unsigned long Overuse = 0;    /* Total calls to free with overused arg */
  42. static char freewarn2[] = "overused buffer";
  43. static char AllocStr[] = "allocs %lu, frees %lu (diff %lu), alloc fails %lu, invalid frees %lu, overused %lu";
  44. #else
  45. static char AllocStr[] = "allocs %lu, frees %lu (diff %lu), alloc fails %lu, invalid frees %lu";
  46. #endif
  47. static char GarbageStr[] = "garbage collections yellow %lu, red %lu";
  48. static char ThreshStr[] = "threshold %lu";
  49.  
  50. static unsigned long Sizes[16] = {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L,
  51.                   0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L };
  52.  
  53. static int logstat (void);
  54.  
  55. static unsigned long availmem (void);
  56. int domemstat (int argc,char *argv[],void *p);
  57. static int dofreelist (int argc,char *argv[],void *p);
  58. static int dothresh (int argc,char *argv[],void *p);
  59. static int dosizes (int argc,char *argv[],void *p);
  60. static int domemdebug (int argc,char *argv[],void *p);
  61. static int dogcollect (int argc,char *argv[],void *p);
  62.  
  63. static struct cmds Memcmds[] = {
  64.     { "debug",    domemdebug,    0, 0, NULLCHAR },
  65.     { "freelist",    dofreelist,    0, 0, NULLCHAR },
  66.     { "gcollect",    dogcollect,    0, 0, NULLCHAR },
  67.     { "sizes",    dosizes,    0, 0, NULLCHAR },
  68.     { "status",    domemstat,    0, 0, NULLCHAR },
  69.     { "thresh",    dothresh,    0, 0, NULLCHAR },
  70.     { NULLCHAR,    NULL,        0, 0, NULLCHAR }
  71. };
  72.  
  73.  
  74. struct header {
  75.     struct header *ptr;
  76.     unsigned long size;
  77. };
  78.  
  79. typedef struct header HEADER;
  80. #define    NULLHDR    (HEADER *)NULL
  81.  
  82. #define    ABLKSIZE    (sizeof (HEADER))
  83.  
  84. static HEADER *morecore (unsigned nu);
  85.  
  86. static HEADER Base;
  87. static HEADER *Allocp = NULLHDR;
  88. static unsigned long Heapsize = 0;
  89.  
  90. #ifdef Kelvdebug
  91. #define MARKER        0x766c654bL /* Kelv in reverse */
  92. #endif
  93.  
  94.  
  95. static void *_malloc (unsigned nb);
  96.  
  97. #if 0
  98. /* Allocate block of 'nb' bytes */
  99. void *
  100. malloc(nb)
  101. unsigned nb;
  102. {
  103. void * retval;
  104.  
  105.     retval = _malloc (nb);
  106.     return (retval);
  107. }
  108. #else
  109. /* Allocate block of 'nb' bytes */
  110. void *
  111. malloc(nb)
  112. unsigned nb;
  113. {
  114.     return mallocw(nb);
  115. }
  116. #endif
  117.  
  118. /* Allocate block of 'nb' bytes */
  119. static void *
  120. _malloc(nb)
  121. unsigned nb;
  122. {
  123.     register HEADER *p, *q;
  124.     register unsigned nu;
  125.     int i;
  126.  
  127.     if(nb == 0)
  128.         return NULL;
  129.  
  130.     /* Record the size of this request */
  131.     if((i = log2((int16) nb)) >= 0)
  132.         Sizes[i]++;
  133.     
  134. #ifndef Kelvdebug
  135.      /* Round up to full block, then add one for header */
  136.  
  137.      nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 2;    /* force allocated memory  */
  138.     nu &= 0xfffffffeL;                /* to be on offset 0x0008 */
  139. #else
  140.      /* Round up to full block, then add one for header and one for debug */
  141.  
  142.      nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 4;    /* force allocated memory  */
  143.     nu &= 0xfffffffeL;                /* to be on offset 0x0008 */
  144. #endif
  145.  
  146.     if ((q = Allocp) == NULLHDR){
  147.         Base.ptr = Allocp = q = &Base;
  148.         Base.size = 1;
  149.     }
  150.  
  151.     for (p = q->ptr; ; q = p, p = p->ptr){
  152.         if (p->size >= nu){
  153.             /* This chunk is at least as large as we need */
  154.             if (p->size <= nu + 1){
  155.                 /* This is either a perfect fit (size == nu)
  156.                  * or the free chunk is just one unit larger.
  157.                  * In either case, alloc the whole thing,
  158.                  * because there's no point in keeping a free
  159.                  * block only large enough to hold the header.
  160.                  */
  161.                 q->ptr = p->ptr;
  162.             } else {
  163.                 /* Carve out piece from end of entry */
  164.                 p->size -= nu;
  165.                 p += p->size;
  166.                 p->size = nu;
  167.             }
  168.             p->ptr = p;    /* for auditing */
  169. #ifdef Kelvdebug
  170.              p->l[(p->size * 2) - 2] = (long)p;    /* debug */
  171.              p->l[(p->size * 2) - 1] = MARKER;    /* debug */
  172. #endif
  173.             Allocs++;
  174.             Availmem -= p->size;
  175.             p++;
  176.             /* On the brain-damaged Intel CPUs in
  177.              * "large data" model, make sure the offset field
  178.              * in the pointer we return isn't null.
  179.              * The Turbo C compiler and certain
  180.              * library functions like strrchr() assume this.
  181.              */
  182.             if(FP_OFF(p) == 0)    /* Return denormalized but equivalent pointer */
  183.                 return (void *)(p - 1);    /*lint !e413 */
  184.  
  185.             return (void *)p;
  186.         }
  187.         if (p == Allocp && ((p = morecore(nu)) == NULLHDR)){
  188.             Memfail++;
  189.             return NULL;
  190.         }
  191.     }
  192. }
  193. /* Get more memory from the system and put it on the heap */
  194. static HEADER *
  195. morecore(nu)
  196. unsigned nu;
  197. {
  198.     void *cp;
  199.     HEADER *up;
  200.     unsigned size;
  201.     void *sbrk(int);    /***/
  202.  
  203.     Morecores++;
  204.     size = nu * ABLKSIZE;
  205.     /* First try to expand our main memory block */
  206.     if((int)(cp = (void *)sbrk((int) size)) != -1){
  207.         up = (HEADER *)cp;
  208.         up->size = nu;
  209.         up->ptr = up;    /* satisfy audit */
  210.         free(up + 1);
  211.         Heapsize += size;
  212.         Frees--;    /* Nullify increment inside free() */
  213.         return Allocp;
  214.     }
  215.     return NULL;
  216. }
  217.  
  218.  
  219. /* Put memory block back on heap */
  220. void
  221. free(blk)
  222. const void *blk;
  223. {
  224.     register HEADER *p, *q;
  225.     unsigned short *ptr;
  226.  
  227.     if(blk == NULL)
  228.         return;        /* Required by ANSI */
  229.     p = (HEADER *)blk - 1;
  230.     /* Audit check */
  231.     if(p->ptr != p){
  232.         ptr = (unsigned short *)&blk;
  233.         tprintf(freewarn,freewarn1,blk,ptr[-1],ptr[-2],Curproc->name,'\n');
  234.         (void) fflush(stdout);
  235.         Invalid++;
  236.         log(-1,freewarn,freewarn1,blk,ptr[-1],ptr[-2],Curproc->name,' ');
  237.         (void) logstat();
  238.         return;
  239.     }
  240. #ifdef Kelvdebug
  241.      if(p->l[(p->size * 2) - 2] != (long)p || p->l[(p->size * 2) - 1] != MARKER){
  242.          ptr = (unsigned short *)&blk;
  243.         tprintf(freewarn,freewarn2,blk,ptr[-1],ptr[-2],Curproc->name,'\n');
  244.         fflush(stdout);
  245.          Overuse++;
  246.         log(-1,freewarn,freewarn2,blk,ptr[-1],ptr[-2],Curproc->name,' ');
  247.         (void) logstat();
  248.          return;
  249.      }
  250. #endif
  251.     Availmem += p->size;
  252.     /* Search the free list looking for the right place to insert */
  253.     for(q = Allocp; !(p > q && p < q->ptr); q = q->ptr){
  254.         /* Highest address on circular list? */
  255.         if(q >= q->ptr && (p > q || p < q->ptr))
  256.             break;
  257.     }
  258.     if(p + p->size == q->ptr){
  259.         /* Combine with front of this entry */
  260.         p->size += q->ptr->size;
  261.         p->ptr = q->ptr->ptr;
  262.     } else {
  263.         /* Link to front of this entry */
  264.         p->ptr = q->ptr;
  265.     }
  266.     if(q + q->size == p){
  267.         /* Combine with end of this entry */
  268.         q->size += p->size;
  269.         q->ptr = p->ptr;
  270.     } else {
  271.         /* Link to end of this entry */
  272.         q->ptr = p;
  273.     }
  274.  
  275.     Frees++;
  276.     if(Memwait != 0)
  277.         (void) ksignal(&Memwait,0);
  278. }
  279.  
  280. #ifdef    notdef    /* Not presently used */
  281. /* Move existing block to new area */
  282. void *
  283. realloc(area,size)
  284. void *area;
  285. unsigned size;
  286. {
  287.     unsigned osize;
  288.     HEADER *hp;
  289.     char *cp;
  290.  
  291.     hp = ((HEADER *)area) - 1;
  292.     osize = (hp->size -1) * ABLKSIZE;
  293.  
  294.     free(area);    /* Hopefully you have your interrupts off , Phil. */
  295.     if((cp = _malloc(size)) != NULL && cp != area)
  296.         memcpy((char *)cp,(char *)area,size>osize? osize : size);
  297.     return cp;
  298. }
  299. /* Allocate block of cleared memory */
  300. void *
  301. calloc(nelem,size)
  302. unsigned nelem;    /* Number of elements */
  303. unsigned size;    /* Size of each element */
  304. {
  305.     register unsigned i;
  306.     register char *cp;
  307.  
  308.     i = nelem * size;
  309.     if((cp = _malloc(i)) != NULL)
  310.         memset(cp,0,i);
  311.     return cp;
  312. }
  313. #endif
  314. /* Version of malloc() that waits if necessary for memory to become available */
  315. void *
  316. mallocw(nb)
  317. unsigned nb;
  318. {
  319.     register void *p;
  320.  
  321.     while((p = _malloc(nb)) == NULL){
  322.         Memwait++;
  323.         kwait(&Memwait);
  324.         Memwait--;
  325.     }
  326.     return p;
  327. }
  328. /* Version of calloc that waits if necessary for memory to become available */
  329. void *
  330. callocw(nelem,size)
  331. unsigned nelem;    /* Number of elements */
  332. unsigned size;    /* Size of each element */
  333. {
  334.     register unsigned i;
  335.     register char *cp;
  336.  
  337.     i = nelem * size;
  338.     cp = mallocw(i);
  339.     memset(cp,0,i);
  340.     return cp;
  341. }
  342. /* Return available memory on our heap plus available system memory */
  343. static unsigned long
  344. availmem()
  345. {
  346. void *p;
  347.  
  348.     if(Availmem*ABLKSIZE >= (uint32) Memthresh)
  349.         return 0;    /* We're clearly OK */
  350.  
  351.     /* There's not enough on the heap; try calling malloc to see if
  352.      * it can get more from the system
  353.      */
  354.     if((p = malloc((int16) Memthresh)) != NULL){
  355.         free(p);
  356.         return 0;    /* Okay */
  357.     }
  358.     if((p = malloc((int16)(Memthresh/2))) != NULL){
  359.         free(p);
  360.         return 1;    /* Yellow alert */
  361.     }
  362.     return 2;        /* Red alert */
  363. }
  364.  
  365. /* Log heap stats */
  366. static int
  367. logstat()
  368. {
  369.     if(Memdebug)    {
  370.         log (-1, "Memory status :");
  371.         log (-1, HeapSizeStr, Heapsize, Availmem * ABLKSIZE, \
  372.             100L * Availmem * ABLKSIZE / Heapsize, Morecores);
  373.         log (-1, AllocStr, Allocs, Frees, Allocs - Frees, Memfail, Invalid
  374. #ifdef Kelvdebug
  375.             , Overuse
  376. #endif
  377.             );
  378.         log (-1, GarbageStr, Yellows, Reds);
  379.         log (-1, ThreshStr, Memthresh);
  380.     }
  381.     return 0;
  382. }
  383.  
  384. void
  385. mbmemory (void)
  386. {
  387.     tputs ("tnos: ");
  388.     tprintf(HeapSizeStr,Heapsize,Availmem*ABLKSIZE, \
  389.         100L*Availmem*ABLKSIZE/Heapsize,Morecores);
  390.     tputc ('\n');
  391. }
  392.  
  393.  
  394.  
  395. static void
  396. dpmistat (void)
  397. {
  398. _go32_dpmi_meminfo info;
  399. __dpmi_version_ret vers;
  400. int needcomma = 0;
  401. unsigned long pagesize;
  402.  
  403.     (void) __dpmi_get_version (&vers);
  404.     tprintf ("\ndpmi: version %d.%d - ", vers.major, vers.minor);
  405.     tprintf ("%-d bit host, %s mode, virtual memory %ssupported\n",
  406.         (vers.flags & 1) ? 32 : 16, (vers.flags & 2) ? "real" : "V86",
  407.         (vers.flags & 4) ? "" : "not ");
  408.     if (__dpmi_get_page_size (&pagesize) != 0)
  409.         pagesize = 0;
  410.     if (_go32_dpmi_get_free_memory_information (&info) == 0)    {
  411.         tprintf ("      avail mem %lu", info.available_memory);
  412.         if (info.linear_space != (unsigned long) -1)
  413.             tprintf (", linear mem %lu", (pagesize) ? info.linear_space * pagesize : info.linear_space);
  414.         if (info.free_linear_space != (unsigned long) -1)
  415.             tprintf (", free linear mem %lu", (pagesize) ? info.free_linear_space * pagesize : info.free_linear_space);
  416.         tputc ('\n');
  417.         if (pagesize)    {
  418.             tprintf ("      page size %lu", pagesize);
  419.             needcomma = 1;
  420.         }
  421.         if (info.total_physical_pages != (unsigned long) -1)    {
  422.             tprintf ("%sphy pages %lu", (needcomma) ? ", " : "      ", info.total_physical_pages);
  423.             needcomma = 1;
  424.         }
  425.         if (info.available_physical_pages != (unsigned long) -1)    {
  426.             tprintf ("%savail phy pages %lu", (needcomma) ? ", " : "      ", info.available_physical_pages);
  427.             needcomma = 1;
  428.         }
  429.         if (needcomma)
  430.             tputc ('\n');
  431.         needcomma = 0;
  432.         if (info.available_pages != (unsigned long) -1)    {
  433.             tprintf ("      avail pages %lu", info.available_pages);
  434.             needcomma = 1;
  435.         }
  436.         if (info.available_lockable_pages != (unsigned long) -1)    {
  437.             tprintf ("%savail lockable pages %lu", (needcomma) ? ", " : "      ", info.available_lockable_pages);
  438.             needcomma = 1;
  439.         }
  440.         if (info.unlocked_pages != (unsigned long) -1)    {
  441.             tprintf ("%savail unlock pages %lu", (needcomma) ? ", " : "      ", info.unlocked_pages);
  442.             needcomma = 1;
  443.         }
  444.         if (needcomma)
  445.             tputc ('\n');
  446.     }
  447. }
  448.  
  449.  
  450.  
  451. /* Print heap stats */
  452. int
  453. domemstat(argc,argv,envp)
  454. int argc;
  455. char *argv[];
  456. void *envp;
  457. {
  458.     mbmemory ();
  459.     tputs ("      ");
  460.     tprintf (AllocStr, Allocs, Frees, Allocs - Frees, Memfail, Invalid
  461. #ifdef Kelvdebug
  462.         , Overuse
  463. #endif
  464.         );
  465.     tputc ('\n');
  466.     tputs ("      ");
  467.     tprintf (GarbageStr, Yellows, Reds);
  468.     dpmistat ();
  469.     return 0;
  470. }
  471.  
  472. /* Print heap free list */
  473. static int
  474. dofreelist(argc,argv,envp)
  475. int argc;
  476. char *argv[];
  477. void *envp;
  478. {
  479.     HEADER *p;
  480.     int i = 0;
  481.  
  482.     for(p = Base.ptr;p != (HEADER *)&Base;p = p->ptr){
  483.         tprintf("%4.4x %6lu", p, p->size * ABLKSIZE);
  484.         if(++i == 5){
  485.             i = 0;
  486.             if(tputc('\n') == EOF)
  487.                 return 0;
  488.         } else
  489.             (void) tputs(" | ");
  490.     }
  491.     if(i != 0)
  492.         tputc('\n');
  493.     return 0;
  494. }
  495. static int
  496. dosizes(argc,argv,p)
  497. int argc;
  498. char *argv[];
  499. void *p;
  500. {
  501.     int i;
  502.  
  503.     for (i = 0; i <= 12; i += 4)    {
  504.         tprintf ("N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld\n",
  505.          1<<i, Sizes[i], 2<<i,Sizes[i+1],
  506.          4<<i, Sizes[i+2], 8<<i,Sizes[i+3]);
  507.     }
  508.     return 0;
  509. }
  510. int
  511. domem(argc,argv,p)
  512. int argc;
  513. char *argv[];
  514. void *p;
  515. {
  516.     return subcmd(Memcmds,argc,argv,p);
  517. }
  518.  
  519. static int
  520. dothresh(argc,argv,p)
  521. int argc;
  522. char *argv[];
  523. void *p;
  524. {
  525.     return setlong(&Memthresh,"Free memory threshold (bytes)",argc,argv);
  526. }
  527.  
  528. static int
  529. dogcollect(argc,argv,p)
  530. int argc;
  531. char *argv[];
  532. void *p;
  533. {
  534. void (**fp)(int);
  535.  
  536.     Yellows++;
  537.     for(fp = Gcollect;*fp != NULL;fp++)
  538.         (**fp)(0);
  539.     (void) tputs ("Garbage collection forced at Yellow level!\n");
  540.     return 0;
  541. }
  542.  
  543.  
  544. void
  545. gcollect(i,v1,v2)
  546. int i;        /* Args not used */
  547. char *v1;
  548. void *v2;
  549. {
  550. void (**fp)(int);
  551. int red = 0;
  552.  
  553.     server_disconnect_io ();
  554.     for ( ; ; ) {
  555.         kpause (1000);
  556.         switch(availmem())    {
  557.             case 0:
  558.                 continue;    /* All is well */
  559.             case 1:
  560.                 red = 0;
  561.                 Yellows++;
  562.                 break;
  563.             case 2:
  564.                 red = 1;
  565.                 Reds++;
  566.                 break;
  567.             default:
  568.                 break;
  569.         }
  570.         for(fp = Gcollect;*fp != NULL;fp++)
  571.             (**fp)(red);
  572.     }
  573. }
  574.  
  575. static int
  576. domemdebug(argc,argv,p)
  577. int argc;
  578. char *argv[];
  579. void *p;
  580. {
  581.     return setbool(&Memdebug,"\"Mem stat\" to log after failures",argc,argv);
  582. }
  583.  
  584. #endif /* !UNIX */
  585.